home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-06-16 | 12.8 KB | 321 lines | [TEXT/CCL2] |
- ;;; -*- package: ASTOOLS -*-
-
- (in-package "ASTOOLS")
-
- (require :aestuff "ccl:applescript/appleevents;aestuff")
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; AppleScript.lisp - T. Bonura 2/3/94
- ;;;
- ;;; Note that this is ® Apple Computer, Inc. 1994. All rights reserved.
- ;;; This file may not be distributed without the consent of Apple Computer.
- ;;;
- ;;; Class definitions for creating applescript CLOS instances.
- ;;; With thanks to Bob Strong
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; Changes:
- ;; Fri, Mar 11, 1994 3:02 PM Changed EXECUTE-APPLESCRIPT to check for an open
- ;; component and also a compiled script id.
- ;; Fri, Mar 11, 1994 3:02 PM Changed EXTRACT-THE-RESULT so that it extracts
- ;; the right thing now - which seems to be an id of 1+ the compiled-script-id.
- ;;; Fri, Mar 25, 1994 2:30 PM Added recordability to the functionality of the ASO.
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; NOTE: Need to work on error handling - Bonura 3/17/94 - 12:10 PM
- ;;; Hmmmm, do I really need this?? -Probably not!
- (DEFTRAP _OSASetDefaultTarget
- ((SCRIPTINGCOMPONENT (:POINTER :COMPONENTINSTANCERECORD))
- (TARGET (:POINTER :AEADDRESSDESC)))
- (:STACK :SIGNED-LONG)
- (:STACK-TRAP #xA82A :D0 0 SCRIPTINGCOMPONENT TARGET ((+ (ASH 4 16) 1029)
- :SIGNED-LONGINT)))
-
-
- (DEFCONSTANT $AppleScript :|ascr| "The applescript scripting component")
- (DEFCONSTANT $GeneralScriptingComponent :|cscr| "The general scripting component")
- (DEFCONSTANT $HyperTalk :|htlk| "The hypertalk scripting component")
-
- (export '(APPLESCRIPT-OBJECT EXECUTE-APPLESCRIPT APPLESCRIPT-OBJECT
- EXECUTE-APPLESCRIPT EXTRACT-THE-RESULT EDIT-SCRIPT))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; Class: APPLESCRIPT-OBJECT
- ;;; OPEN-COMPONENT ((ASO APPLESCRIPT-OBJECT)) "opens a scripting component
- ;;; and sets the value of the component slot to a pointer
- ;;; COMPILE-APPLESCRIPT ((ASO APPLESCRIPT-OBJECT)) "compiles the script
- ;;; which is in the script slot"
- ;;; EXECUTE-APPLESCRIPT ((ASO APPLESCRIPT-OBJECT)) "What do you think?"
- ;;; EDIT-SCRIPT ((ASO APPLESCRIPT-OBJECT))
- ;;; CLEANUP ((ASO APPLESCRIPT-OBJECT))
- ;;; DISPOSE-SCRIPT ((ASO APPLESCRIPT-OBJECT))
- ;;; DISPLAY-RESULT ((ASO APPLESCRIPT-OBJECT))
- ;;; EXTRACT-THE-RESULT ((ASO APPLESCRIPT-OBJECT))
- ;;; ****** Recording *****
- ;;; START-RECORDING ((ASO APPLESCRIPT-OBJECT))
- ;;; STOP-RECORDING ((ASO APPLESCRIPT-OBJECT)) "When we
- ;;; stop recording, we add the decompiled script to the script slot"
- ;;; DECOMPILE-SCRIPT ((ASO APPLESCRIPT-OBJECT))
- ;;; ** ASO = AppleScriptObject **
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (DEFCLASS APPLESCRIPT-OBJECT (standard-object)
- ((script :initform NIL :initarg :script :accessor script)
- (application-name :initform NIL :initarg :application-name :accessor
- application-name)
- (scripting.component.type :initform NIL :initarg :scripting-component-type
- :accessor scripting-component-type)
- ;; NOTE: the as.target slot is not currently used
- (as.target :initform NIL :initarg :target :accessor as-target)
- (break.on.error :initarg :break-on-error :accessor break-on-error)
- (compiled.script :initform NIL :initarg NIL :accessor compiled-script)
- (compiled.script.id :initform NIL :initarg NIL :accessor compiled-script-id)
- (component :initform nil :initarg :component :accessor component)
- (returned.value :accessor returned-value)
- )
- (:default-initargs
- :scripting-component-type $AppleScript
- :break-on-error t)
- )
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (DEFGENERIC OPEN-COMPONENT (APPLESCRIPT-OBJECT)
- (:documentation "Opens a scripting component")
- )
-
- (DEFMETHOD OPEN-COMPONENT ((ASO APPLESCRIPT-OBJECT))
- (setf (component ASO)
- (#_OpenDefaultComponent #$kOSAComponentType
- (scripting-component-type ASO))))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (DEFGENERIC COMPILE-APPLESCRIPT (APPLESCRIPT-OBJECT)
- (:documentation "Compile the applescript")
- )
-
- (DEFMETHOD COMPILE-APPLESCRIPT ((ASO APPLESCRIPT-OBJECT))
- (unless (component aso)
- (open-component aso))
- (with-pointers ((as (component ASO)))
- (let ((text (extract-script-text (script ASO))))
- (with-aedescs (source)
- (let ((size (length text)))
- (%vstack-block (buff size)
- (dotimes (i size)
- (%put-byte buff (char-code (char text i)) i))
- (#_AECreateDesc #$typeChar buff size source)))
- (rlet ((id :OSAID))
- (%put-long id #$kOSANullScript)
- (let ((err (#_OSACompile as source 0 id)))
- (cond ((zerop err)
- ;;(format t "OK Seems to compile")
- (setf (compiled-script aso) t)
- (setf (compiled-script-id ASO) (%get-long id)))
- (t
- (if (break-on-error ASO)
- (error (script-error as)))
- (values nil err))))))
- )
- )
- )
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (DEFGENERIC EXECUTE-APPLESCRIPT (APPLESCRIPT-OBJECT)
- (:documentation "Execute the script on the target")
- )
-
- (DEFMETHOD EXECUTE-APPLESCRIPT ((ASO APPLESCRIPT-OBJECT))
- ;; in case we try to execute without having an open scripting component
- (unless (component ASO)
- (open-component ASO))
- ;; whenever the script is edited in the script editor, the value of
- ;; compiled-script is set to nil
- (unless (compiled-script aso)
- (compile-applescript ASO))
- (with-pointers ((as (component ASO)))
- ;; maybe not yet compiled?
- (unless (compiled-script-id ASO)
- (compile-applescript ASO))
- (rlet ((result-id :OSAID))
- (let* ((id (compiled-script-id ASO))
- (err (#_OSAExecute as id 0 0 result-id)))
- (cond ((zerop err)
- ;(%get-long result-id)
- (extract-the-result aso))
- (t
- (if (break-on-error ASO)
- (error (script-error as)))
- (values nil err)))))
- )
- )
-
- (DEFMETHOD EXTRACT-THE-RESULT ((ASO APPLESCRIPT-OBJECT))
- (with-aedescs (source)
- ;; the second parameter to OSADisplay should be an id. If I pass the id
- ;; which is generated when I compile the script I don't necessarliy get the
- ;; right thing - if I pass 1 + that value I do!.
- ;; What's going on?
- (let ((err (#_OSADisplay (component ASO) (1+ (compiled-script-id aso))
- #$typeChar 0 source)))
- (cond ((zerop err)
- (setf (returned-value aso)
- (get-string (rref source AEDesc.dataHandle))))
- (t (values nil err))))))
-
- (DEFMETHOD DISPLAY-RESULT ((ASO APPLESCRIPT-OBJECT))
- (format t "~%~A" (extract-the-result ASO)))
-
- (DEFMETHOD DISPOSE-SCRIPT ((ASO APPLESCRIPT-OBJECT))
- (let ((as (component ASO))
- (id (compiled-script-id ASO)))
- (if (and as id)
- (assert (zerop (#_OSADispose as id))))
- )
- )
-
- (DEFMETHOD CLEANUP ((ASO APPLESCRIPT-OBJECT))
- (dispose-script ASO) ; what else??
- )
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (DEFGENERIC EDIT-SCRIPT (APPLESCRIPT-OBJECT)
- (:documentation "Bring up a script editor on the script")
- )
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; Methods for dealing with error conditions
- ;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;;
- ;;; Recording From Recordable Applications
- ;;; The following allows for recording to be turned on.
- ;;; Actions are recorded to the compiled script in the
- ;;; applescript object.
- ;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (DEFMETHOD START-RECORDING ((aso APPLESCRIPT-OBJECT))
- ;; tell the applescript object to start recording
- ;; tell the object to open a scripting component
- (open-component aso)
- ;; if there is a compiledscriptid then we use it
- ;; otherwise we use the null script
- (unless (compiled-script-id aso)
- (with-pointers ((as (component aso)))
- (rlet ((id :OSAID))
- (%put-long id #$KOSANullScript)
- (let ((oserr (#_OSAStartRecording as id)))
- (if (zerop oserr)
- (progn
- (format t "Recording is on.~%")
- (setf (compiled-script-id aso) (%get-long id)))
- (if (break-on-error ASO)
- (error (script-error as)))))))))
-
-
- (DEFMETHOD STOP-RECORDING ((aso APPLESCRIPT-OBJECT))
- (with-pointers ((as (component aso)))
- (let ((oserr (#_OSAStopRecording as (compiled-script-id aso))))
-
- (cond ((zerop oserr)
- (decompile-script aso)
- (format t "Recording is off.~%"))
- (t
- (if (break-on-error ASO)
- (error (script-error as))))))))
-
-
- (DEFMETHOD DECOMPILE-SCRIPT ((aso applescript-object))
- ;; extract the script from the compiled script. Most
- ;; useful when doing recording
- (with-pointers ((as (component aso)))
- (let* ((descObj (make-instance 'ccl::aedesc :type #$TypeChar))
- (id (compiled-script-id aso))
- (err (#_OSAGetSource as id #$typeChar
- (ccl::getDescRecPtr descObj))))
- (cond ((zerop err)
- ;; extract the text from the descriptor, then
- ;; add the script to the script slot of the
- ;; object and inform the object that the
- ;; script has changed
- (setf (script aso)
- (get-string (rref (ccl::getDescRecPtr descObj)
- AEDesc.dataHandle))
- (compiled-script aso) t))
- (t (if (break-on-error ASO)
- (error (script-error as)))
- )
- )
- )
- )
- )
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; Utilities
- ;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (DEFUN EXTRACT-SCRIPT-TEXT (text)
- "Remove any tabs and linefeeds from the text if the script should be of short
- form, otherwise if the script is of the type 'tell, end tell' just return the
- whole thing"
- ;; see if the last word of the text is "tell"
- (if (string= "tell" (reverse (string-downcase (subseq (reverse text) 0 4))))
- text
- (strip-lf&tab text)))
-
- (DEFUN STRIP-LF&TAB (string)
- "Removes linefeeds and tabs from a copy of string"
- (substitute-if #\space #'(lambda (char)
- (or (char= char #\return)
- (char= char #\tab)))
- string))
-
- (DEFUN GET-STRING (data)
- (let* ((size (#_GetHandleSize data))
- (text (make-string size)))
- (dotimes (i size)
- (setf (char text i) (code-char (%hget-byte data i))))
- text))
-
- (DEFUN SCRIPT-ERROR (as)
- (with-aedescs (err)
- (if (/= (#_OSAScriptError as #$kOSAErrorMessage #$typeChar err) #$noErr)
- ""
- (get-string (rref err AEDesc.dataHandle)))))
-
-
- (provide :appleScript)
-
-
- #|
-
- (setf ttest (make-instance 'applescript-object))
- (start-recording ttest)
- (stop-recording ttest)
- (inspect ttest)
- (execute-applescript ttest)
-
- (decompile-script ttest)
-
-
- (setf astest (make-instance 'APPLESCRIPT-OBJECT
- :script "tell application \"Eudora\" to get the number of Message of Mailbox \"In\" of Mail Folder \"\""
- :application-name "Eudora"
- ))
- (open-component astest)
- (compile-applescript astest)
- (execute-applescript astest)
- (edit-script astest)
- (cleanup astest)
- Here are some scripts which seem to work:
- "tell application \"Eudora2.0.2a1d-2.1994\" to make new Message at the end of Mailbox \"out\" of Mail Folder \"\""
- "tell application \"Eudora2.0.2a1d-2.1994\" to Connect with send and check"
- "tell application \"Eudora2.0.2a1d-2.1994\" to Reply Message 4 of Mailbox \"In\" of Mail Folder \"\""
- "tell application \"Eudora2.0.2a1d-2.1994\" to Redirect the last Message of Mailbox \"In\" of Mail Folder \"\""
- "tell application \"Eudora2.0.2a1d-2.1994\" to get the Field \"to\" of the last Message of Mailbox \"In\" of Mail Folder \"\""
- "tell application \"Eudora2.0.2a1d-2.1994\" to get the number of Message of Mailbox \"In\" of Mail Folder \"\""
- "tell application \"Eudora2.0.2a1d-2.1994\" to Connect without Send"
-
- ;; here's one for :|quil|
- "tell \"Scriptable Text Editor\" to set the size of word 1 of window 1 of application \"Scriptable Text Editor\" to 48"
-
- |#
-